package com.cskaoyan.javase.oop2._1extends._6initialization._1basic;

/**
 * @description: 子类对象的初始化过程
 * @author: wuguidong@cskaoyan.onaliyun.com
 **/

import sun.swing.plaf.synth.DefaultSynthStyle;

/**
 * 练习
 * - 创建一个Person类，有name属性和eat方法
 * - 创建一个Star类，有stageName属性和sing方法
 * - Star类要继承Person类
 * - 创建Star类对象，画出这个过程的内存图
 *
 * 在创建Star对象的过程中,首先要考虑类加载,并且由于Star有父类Person,子类的类加载会触发父类的类加载,
 *      并且类加载的顺序是"先父后子"的
 * 总结类加载的时机:
 *      a.启动main方法
 *      b.创建对象
 *      c.访问类的静态成员
 *      d.子类类加载会触发父类类加载(不管子类是何种方式触发类加载)
 *
 * 类加载结束后,开始创建对象,要明确的是,只会创建子类对象本身,而不会创建父类对象,堆上只有一个子类对象,没有任何父类对象
 *
 * 接下来子类对象中会专门开辟一片独立的区域,用来存储父类的成员变量,子类自身独有的成员变量也会存储在自身对象中
 * 对于父子类的成员变量的赋值:
 *      a.它们的默认初始化具有默认值的过程,不需要去考虑它们的先后顺序(实际上在对象的成员变量的其他赋值方式开始赋值时,它们已经具有了默认值)
 *      b.它们除了默认初始化外的其它赋值方式,是"先父后子"的
 *
 * 创建子类对象时,类加载的先父后子是JVM去保证的,但是成员赋值顺序的"先父后子"是怎么保证的呢?
 *      是通过父子类构造器调用的"先父后子"保证的
 *      如果父类的构造器先于子类构造器执行:
 *          那么父类所有的成员变量的赋值方式都是先于子类成员变量的任何赋值方式(默认初始化除外)
 *
 * 思考: 为什么父类的构造器要执行?
 *
 * 子类对象的隐式初始化:
 *      在java的任何构造器当中,如果第一行没有this、super去明确的调用别的构造器，那么永远隐含了一条语句：
 *      super();
 *      表示去调用父类的无参构造方法
 *      这样就能够保证，父类成员变量的赋值一定先于子类
 *
 * 子类对象的隐式初始化是调用父类无参构造方法，没有办法完成父类成员变量的赋值，
 *      所以就需要子类对象的显式初始化，明确在构造器的第一行，用super(参数)，明确指出调用父类的某个构造方法
 *      这种在子类构造器的第一行用super(参数)明确指出调用父类构造器的
 *          子类对象的初始化方式称之为子类对象的显式初始化
 *
 * 注意事项:
 *      1.在子类对象创建的过程中，父类的构造方法会被调用，但是不会创建父类的对象
 *      2.super在子类构造器中用于表示调用父类构造器时，例如super(参数)
 *          这条语句必须在构造器的第一行
 *      3.this在子类构造器用于表示调用自身构造器时，例如this(参数)
 *          这条语句必须在构造器的第一行
 *          那么super和this在表示调用构造器时，是不能共存的
 *      4.类加载是"先父后子"的,像Object,String,System等jdk中已经定义好的类,
 *          它们也是需要类加载的(只不过类加载的类加载器不同)
 *
 *
 */
public class Demo {
    public static void main(String[] args) {
        //Star s = new Star();
        //System.out.println(s.stageName);

        Star s = new Star("马云");
        System.out.println(s.name);
        System.out.println(s.stageName);

        Star s2 = new Star("张含韵", "张韶涵");
        System.out.println(s2.name);
        System.out.println(s2.stageName);
    }
}

class Person {
    /*static {
        System.out.println("Person类加载了~");
    }*/

    {
        System.out.println("Person构造代码执行~");
    }

    String name = "长风";

    public void eat() {
        System.out.println("干饭!");
    }

    public Person() {
    }

    public Person(String name) {
        this.name = name;
    }
}

class Star extends Person {
    /*static {
        System.out.println("Star类加载了~");
    }*/

    {
        System.out.println("Star构造代码执行~");
    }

    String stageName = name + "的弟弟"; //艺名/花名

    public void sing() {
        System.out.println("唱歌");
    }

    public Star() {
        super();
    }

    public Star(String name) {
        super(name);
    }

    public Star(String name, String stageName) {
        //Call to 'super()' must be first statement in constructor body
        super(name);
        this.stageName = stageName;

    }
}
